5. How to keep multiple values in a variable - Lists and Tuples (arrays)

  1. A new data type - lists
    • So far we used A VARIABLE to store ONE value. What if we want to store multiple values? For example, what if we want to read 100 integers from the user and save them in variables? Do we have to use 100 different variables?
    • Let's try the next example that reads multiple integers from the user.
      • for i in range(10):
            num = int(input("Enter an integer: "))
        
      • The above example reads 10 integers and save them into one variable.
      • How to save them in different variables, like num0, num1, ..., num9? What if we need to read a million values for the statistical analysis?
    • Let's try another example that reads multiple integers from the user. In this example, the user decides how many integers will be entered.
      • howmany = ???(input("Enther number of integers: "))    # int() converts a string to an integer.
        for i in ???(howmany):
            num = ???(input("Enter an integer: "))
        
      • The above example reads howmany-many integers and save them into one variable.
      • How to save them in different variables? It is not possible to decide what howmany the user will input. What do we have to do?
    • A list is a data type, and a list value that can hold multiple other values. How? Multiple values are listed with in two [ and ], and the values are separated by commas.
      • Here are examples.
        numbers = [10, -2, 3, 99, 0]    # Comma separated values with in [ and ]
        names = ["John", "Ruth", "Tom"]
        record = ["CS", 4, 3.9, True]
        print(record)
        
      • How to access each value in a list? Each value has an index, i.e., position number in the list, from 0 up to the total number of values - 1. Index values should be integers, not float. How to access the value of index 2? Here is an example.
        numbers = [10, -2, 3, 99, 0]    # The index of 10 is 0, and the index of -2 is 1, ...
        print(numbers[2])    # the value of index 2 in numbers.
        print(numbers[0])
        print(["CS", 4, 3.9, True][1])    # possible?
        
        numbers[0], ..., numbers[4] are individual variables, and they are called elements.
      • What if we try to access wrong indexes? Let's try the next example.
        numbers = [10, -2, 3, 99, 0]
        print(numbers[-1])    # ???
        print(numbers[5])     # IndexError: list index out of range
        ["CS", 4, 3.9, True][10]    # IndexError: list index out of range
        
        Anything strange with print(numbers[-1])?
      • Indexes can be negative integers. Let's try the next examples.
        numbers = [10, -2, 3, 99, 0]
        print(numbers[1])    # 
        print(numbers[0])    # 
        print(numbers[-1])    # 
        print(numbers[-2])    # 
        print(numbers[-3])    # 
        print(numbers[-4])    # 
        print(numbers[-5])    # 
        print(numbers[-6])    # IndexError: list index out of range
        
  2. Operations on lists
    • How to change a value in a lists?
      • We can assigne a new value to an element of the list. Let's try the next example.
        numbers = [10, -2, 3, 99, 0]
        numbers[2] = -8
        print(numbers)
        
    • How to add a new value to a list?
      • Let's try the next example.
        numbers = []    # An empty list
        numbers = numbers + [10]    # +: list concatenation operator
        numbers = numbers + [-2]
        numbers = numbers + [3] + [99, 0]
        print(numbers)
        
    • How to add two lists?
      • Let's try the next example.
        numbers = [10, -2, 3, 99, 0]
        names = ["John", "Ruth", "Tom"]
        test = numbers + names
        print(test)
        
    • How to delete an element?
      • Let's try the next example.
        numbers = [10, -2, 3, 99, 0]
        del numbers[1]    # del statement: Deletes a variable, the specifed element in this case
        del(number[1])    # del() function
        print(numbers)
        
    • How to check if a value is stored in a list?
      • Let's try the next example.
        numbers = [10, -2, 3, 99, 0]
        result = 3 in numbers    # in: list membership operator
        print(result)
        result = 3 not in numbers    # not in: list membership operator
        print(result)
        result = '99' in numbers    # The string '99' will be converted to an integer 99 first, and then in operator.
        print(result)
        
        numbers = []
        for i in range(1000):
            numbers = numbers + [int(input('Enter integer: '))]
            if -1 in numbers:
                break;
        print(numbers)
        
  3. Loop with a list
    • How to go through all the elements in a list? Let's try the next example.
      numbers = [10, -2, 3, 99, 0]
      for i in numbers:
          print(i)    # Prints elements, not indexes
      
    • How to use all the elements in a list? An idea is to use all the elements with index values from 0 to the last. How to get the last index? We need to know the number of elements in a list, i.e., the length of the list. Let's try the next example.
      numbers = [10, -2, 3, 99, 0]
      count = ???(numbers)    # len(): the function that was used to get the length of a string.
      for i in range(count):
          print(numbers[i])    # Prints the ith element
      
    • How to read inputs and store them in a list?
      • One idea is to create a list of the certain number of elements, and save inputs into the list. Let's try the next example.
        numbers = [None, None, None, None, None]    # None: a special value meanging that nothing is assigned
        for i in ???(5):
            numbers[i] = ???(input('Enter an integer: '))
        print(numbers)
        
        What if we need to read a million values?
      • What if the user decides the number inputs? In this case, the program cannot decide how many inputs will be read, and the above example cannot be used.
      • Another idea is to start with an empty list and concatenate an element by element. Let's try the next example.
        numbers = []    # Empty list
        count = int(input('Enter the number of inputs: '))
        for i in range(???):    # count-many times
            value = int(input('Enter an integer: '))
            numbers = numbers ??? ???    # +: list concatenation operator
        print(numbers)
        
      • Another idea is to start with an empty list and append an element by element, using the .append() method. Note a method is a function belonging to an object. Let's try the next example.
        numbers = []    # Empty list
        count = int(input('Enter the number of inputs: '))
        for i in range(count):
            value = int(input('Enter an integer: '))
            numbers.append(value)    # .append() method: appends a new element; A method is a function belonging to an object. In this example, the list numbers.
        print(numbers)
        
  4. List methods
    • A method is a function that belongs to an object. E.g., .append() is used to append a new element to a list.
      numbers.append(20)
      
    • .index() - It decides the index with a passed value.
      numbers = [10, -2, 3, 99, 0]
      index = numbers.index(-2)
      print(index)
      value = input("Enter a value: ")
      index = numbers.index(value)    # Be careful that value has a string, not integer.
      print(index)
      
      How to fix?
      What if an integer that is not in the list is passed?
    • .insert() - It inserts a value into a specified indexed element.
      numbers = [10, -2, 3, 99, 0]
      numbers.insert(2, 7)  # 7 into numbers[2]
      print(numbers)
      
    • .remove() - It removes the first encountering element that has the specified value.
      numbers = [10, -2, 3, 99, 0]
      numbers.insert(2, 99)
      numbers.remove(99)
      print(numbers)    # What results?
      
      What if a number that is not in the list?
    • .sort() - It sorts all the elements in ascending order.
      numbers = [10, -2, 3, 99, 0]
      numbers.sort()
      print(numbers)    # What results?
      names = ["John", "Ruth", "Tom", "dog", "cat", "zebra"]
      names.sort()    # Upper letters first
      print(names)
      names = ["John", "Ruth", "Tom", "dog", "cat", "zebra"]
      names.sort(key=str.lower)    # In dictionary order; let's just use key=str.lower for a while. 
      print(names)
      record = ["CS", 4, 3.9, True]
      record.sort()    # Anything wrong here?
      print(record)
      
    • How to sort in descending order? .sort(reverse=True), where reverse is a keyword argument
      numbers = [10, -2, 3, 99, 0]
      numbers.sort(reverse=True)
      print(numbers)    # What results?
      
    • How to reverse the values in a list? .reverse()
      numbers = [10, -2, 3, 99, 0]
      numbers.reverse()
      print(numbers)    # What results?
      
  5. Sequence data types and operations
    • How to take out a sublist from a list?
      numbers = [10, -2, 3, 99, 0]
      newNumbers = numbers[2:4]    # numbers[1], ..., numbers[4-1] will be taken out.
      print(newNumbers)    # What results?
      
    • How to take out a substring from a string?
      msg = 'What a wonderful programming language, Python'
      newMsg = msg[5:16]    # msg[5], ..., msg[16-1] will be taken out.
      print(newMsg)    # What results?
      
    • Lists, string, tuples that we will discuss later soon, and the return objects from range() are called sequence data types. The above sub-sequence operation is supported. in and not in operations are also supported. for loops can be used with them. Let's try the next example.
      name = 'Williams'
      print('l' in name)    # ???
      print('l' not in name)    # ???
      print(name[2:5])    # ???
      print(name[6])    # ???
      print(len(name))    # ???
      for c in name:
          print(c)
      
  6. A list of lists
    • The values in a list can be any data type, including list, which means we can use a list of lists. Let's try the next example.
      student1 = ['John', 20, 'COMP']
      student2 = ['Ruth', 19, 'MATH']
      students = [student1, student2, ['Tom', 21, 'COMP']]
      print(students)
      print(students[0])
      print((students[1])[2])
      print(students[1][2])
      
    • In the above example, students[1] has ['Ruth', 19, 'MATH']. This is why (students[1])[2] has 'MATH'. (students[i])[j] can be denoted as students[i][j].
  7. Assignment operators
    • Any way to shorten the next assignments, sum = sum + 10 or sum = sum / 10? Let's try the next example.
      sum = 0
      for i in range(5):
          value = input('Enter a value: ')
          value = int(value)
          sum = sum + value
      print(sum)
      
      Let's try another example.
      ????
      for i in range(5):
          value = input("Enter a value: ")
          value = int(value)
          sum += value    # +=: addition assignment operator
      print(sum)
      
    • Similar assignment operators for - * / % //
      ????
      sum += 5
      sum -= 5    # sum = sum - 5
      sum ??? 5    # sum = sum * 5
      sum ??? 5    # sum = sum / 5
      sum ??? 5    # sum = sum % 5
      sum ??? 5    # sum = sum // 5
      
  8. Another new data type - tuples
    • A tuple is similar to a list. The differences are
      • (...) is used instead of [...]. But [...] is used to access elements.
      • Tuples are NOT mutable like strings. That is that the values in a tuple cannot be modified, appended, or removed.
    • Let's try the next example.
      record = ('John', 20, 'COMP')
      print(type(record))  # type() to check the data of a variable or value
      print(record[1])
      r = record[0:2]
      print(r)
      record[2] = 'MATH'  # ???
      
  9. How to convert a tuple to a list, or a list to a tuple
    • How to convert a string to an integer? Here is an example. number = int('345')
    • Data type functions, data_type(), are used to change the data type of a variable or value.
    • Let's try the next example.
      record = ('John', 20, 'COMP')
      print(record)
      recordList = list(record)  # list()
      print(recordList)
      recordTuple = tuple(recordList)  # tuple()
      print(recordTuple)
      
  10. Reference data types
    • When an integer is stored in a variable, the value is stored in variable. When the variable is copied to another variable, the value stored in the first variable is copied to the other variable. Hence the two variables hold the same integer value, but in different memory locations.
    • Let's try the next example.
      size1 = 123
      size2 = size1
      print(size1)  # ???
      print(size2)  # ???
      size1 = 345
      print(size1)  # ???
      print(size2)  # ???
      
    • Lists, tuples, and strings are different. When a list value is stored in a variable, the list value is stored in a memory location, and the reference (orc address) of the memory location is stored in the variable. When the list variable is copied to another variable, the reference value stored in the first variable is copied to the other variable, so that the two variables have the same reference value pointing to the same list value in the memory. Hence when the first variable is modified, we can see that the second variable is modified. This is because the two variables hold the same reference of the list value.
    • Lists, tuples, and strings are called reference types.
    • How to check reference values? id() funtion - id for identity.
    • Let's try the next example for lists.
      record1 = ['John', 20, 'COMP']
      record2 = record1
      print('record1 = ' + str(record1))
      print('record2 = ' + str(record2))
      print('The reference stored in record1 = ' + str(id(record1)))
      print('The reference stored in record2 = ' + str(id(record2)))
      del(record1[1])
      record1.append('Interesting')
      print('record1 = ' + str(record1))
      print('record2 = ' + str(record2))
      print('The reference stored in record1 = ' + str(id(record1)))
      print('The reference stored in record2 = ' + str(id(record2)))
      
    • Let's try the next example for tuples.
      record1 = ('John', 20, 'COMP')
      record2 = record1
      print('record1 = ' + str(record1))
      print('record2 = ' + str(record2))
      print('The reference stored in record1 = ' + str(id(record1)))
      print('The reference stored in record2 = ' + str(id(record2)))
      del(record1)  # The variable record1 that holds a reference value is deleted.
                    # But the tuple value is still referred from record2
      #print('record1 = ' + str(record1))  # We cannot use record1 anymore.
      print('record2 = ' + str(record2))
      print('The reference stored in record2 = ' + str(id(record2)))
      
    • One thing that we need to remember when we use reference type values is the actual values are accessed through their references stored in variables.
  11. Passing references to a function
    • One thing that we need to remember when we use reference type values is the actual values are accessed through their references stored in variables. When a reference variable is passed to a function, not like non-reference types such as integer and float, the reference value stored in the variable, not the actual value, is passed. (Note. When we consider non-reference type values are directly stored in variables, the variable passing is the same for both of non-reference type and reference types.)
    • Let's try the next example for integers.
      def add(size):
          size += 2
      
      num = 20
      print(num)
      add(num)
      print(num)  # 20 or 22 ???
      
    • Let's try the next example for lists.
      def append(r):
          r.append('Kamloops')
      
      record = ['John', 20, 'COMP']
      print(record)
      append(record)
      print(record)  # ???
      
    • Let's try another example for lists. How to increase all the values in a list by 2?
      def increase(l, b):  # increase all the values in l by b
          for i in range(????):  # how to get the length of a list?
              l[i] ????
      
      marks = []
      for i in ???(5):  # 5 integers
          marks.append(int(input("Integer: ")))
      print(marks)
      
      increase(marks, 5)
      print(marks)  # ???
      
  12. How to copy reference type values, not their references
    • Let's try the next example. The two variables refer to the same list value, i.e., the reference of the list value is copied to the second varible.
      record1 = ['John', 20, 'COMP']
      record2 = record1
      print('record1 = ' + str(record1))
      print('record2 = ' + str(record2))
      print('The reference stored in record1 = ' + str(id(record1)))
      print('The reference stored in record2 = ' + str(id(record2)))
      
    • How to copy the list value, not the reference value? One idea is to use the module copy.
      import copy
      
      record1 = ['John', 20, 'COMP', ['Kamloops', 'BC', 'Canada']]
      record2 = copy.copy(record1)  # copy the value, not the reference; but the refernce of ['Kamloops', 'BC', 'Canada'] is copied.
      print('The reference stored in record1 = ' + str(id(record1)))
      print('The reference stored in record2 = ' + str(id(record2)))  # the same?
      record1[0] = 'Tom'
      record1[3][0] = 'Chase'
      print('record1 = ' + str(record1))
      print('record2 = ' + str(record2))
      
      record2 = copy.deepcopy(record1)  # copy the value, not the reference; even list elements
      print('The reference stored in record1 = ' + str(id(record1)))
      print('The reference stored in record2 = ' + str(id(record2)))  # the same?
      record1[3][0] = 'Kamloops'
      print('record1 = ' + str(record1))
      print('record2 = ' + str(record2))
      
    • What if one element of a list value is another list? E.g., [1, 2, [3, 4], 5]]? The reference of [3, 4] will be copied with copy(). We may investigate the deepcopy() function to copy even elements.
  13. Programming exercises
    1. Write a program that reads a certain number of integers, saves them into a list, computes the average with the list, and prints the result.
    2. Write a function that is passed with a list of integers, and sorts the values in the list. Write a program that reads integers and stores them into a list, and sorts the list using the above function.
    3. Tic-tac-toe game
      • Write a function that receives a list and prints the elements. The elements should be separated by '|'. E.g., row = ['O', 'O', 'X'] will be printed as O|O|X.
      • Write a function that receives a list, an index, and a string. The function assigns the string to the index of the list.
    4. 3×3 puzzle game
      • Write a function that receives a list. It selects two elements randomly and swaps them.
      • Write a function that receives two integers from and to. It makes a list of randomly scattered numbers from to to. It returns the list.
      • Write a function that receives a list and prints the elements. The elements should be separated by '|'. 0 should be replace by a space. E.g., row = [2, 0, 4] will be printed as |2| |4|.
    5. 1-D Mine sweeper game
      • Write the function that makes a list of characters. The length of the list is 10, 3 characters are 'M', and all the other characters are ' '. The position of 'M' should be randomly decided. The function returns the list.
      • Write the function that receives a list of charaters, which is the return value from the above function. The function checks all the elements in the list, so that an element not having 'M' is replaced by
        • '0' if there is no neighbor element having 'M', or
        • '1' if there is one neighbor element having 'M', or
        • '2' if two neighbor elements have 'M'.
        E.g., ['M',' ',' ',' ',' ','M',' ','M',' ',' '] becomes ['M','1','0','0','1','M','2','M','1','0'].
        The function returns the updated list.
      • Write the function that receives a list of characters and prints the list in the way that all the characters are separated by '|'. E.g., |M|1|0|0|1|M|2|M|1|0| for board = ['M','1','0','0','1','M','2','M','1','0']. Anoter example, | | |0| |1| | | | | | for board = [' ',' ','0',' ','1',' ',' ',' ',' ',' '].
      • Write the 1-D mine sweeper program in which
        • in a loop, the program reads a tuple (i, c), where i for the position and c for the guess for '0', '1', '2', or 'M'.
        • Hint. You may use another list having the initial values of ' '.
  14. References